using System;
using System.IO;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

using GameLib;

// Farseer Physics Library.
using FarseerGames.FarseerPhysics;
using FarseerGames.FarseerPhysics.Collisions;
using FarseerGames.FarseerPhysics.Dynamics;
using FarseerGames.FarseerPhysics.Factories;
using FarseerGames.FarseerPhysics.Controllers;
using FarseerGames.FarseerPhysics.Interfaces;

namespace TileEngine
{
    public class Level : GameComponent
    {
        private Tile[] tiles;
        private string levelPath;
        public Map map;

        public Player player;  

        public Level(Game game, int id)
            : base(game)
        {
            player = new Player(this);
            levelPath = Game.Content.RootDirectory + @"\level" + id.ToString() + ".txt";
        }

        public void SetMap(Map map)
        {
            this.map = map;
        }

        public override void Initialize()
        { 
            base.Initialize();
        }

        public void Load(ref PhysicsSimulator physicsSimulator)
        {
            player.Load(ref physicsSimulator);
            LoadMap(ref physicsSimulator);
        }
       
        public override void Update(GameTime gameTime)
        {
            player.Update(gameTime);
            
            base.Update(gameTime);
        }

        public void LoadMap(ref PhysicsSimulator physicsSimulator)
        {
            tiles = new Tile[(int)(map.Size.X * map.Size.Y)];

            // Fill the tile array with the values from the baselayer.
            for (int t = 0; t < tiles.Length; t++)
            {
                tiles[t] = LoadTile(map.BaseLayer[t]);
            }

            int currentTile = 0;
            for (int row = 0; row < map.Size.Y; row++)
            {
                for (int col = 0; col < map.Size.X; col++)
                {
                    if (tiles[currentTile].Collision == TileCollision.Impassable)
                    {
                        tiles[currentTile].Body = BodyFactory.Instance.CreateRectangleBody(physicsSimulator, map.TileSize.X, map.TileSize.Y, 1);

                        tiles[currentTile].Body.Position = new Vector2(col * map.TileSize.X, row * map.TileSize.Y);
                        tiles[currentTile].Body.IsStatic = true;   
                        tiles[currentTile].Geom = GeomFactory.Instance.CreateRectangleGeom(physicsSimulator, tiles[currentTile].Body, map.TileSize.X, map.TileSize.Y);
                    }
                    currentTile++;
                }
            }
        }        

        private Tile LoadTile(string name, TileCollision tileCollision)
        {
            return new Tile(Game.Content.Load<Texture2D>(@"Textures\tiles\" + name), tileCollision);
        }

        private Tile LoadTile(int tilesType)
        {
            if (tilesType != 0)
            {
                try
                {
                    return LoadTile("sand_tiles_0" + tilesType.ToString(), TileCollision.Impassable);
                }
                catch (ContentLoadException)
                {
                    throw new NotSupportedException("Tile type not found!");
                }
            }
            else
            {
                return new Tile(null, TileCollision.Passable);
            }
        }        

        public void DrawTiles(SpriteBatch spriteBatch)
        {
            int currentTile = 0;
            for (int row = 0; row < map.Size.Y; row++)
            {
                for (int col = 0; col < map.Size.X; col++)
                {           
                    if (tiles[currentTile].Body != null)
                    {
                        // Draw it in screen space.                        
                        spriteBatch.Draw(tiles[currentTile].Texture, new Vector2(tiles[currentTile].Body.Position.X, tiles[currentTile].Body.Position.Y), null, Color.White, tiles[currentTile].Body.Rotation, new Vector2(map.TileSize.X / 2, map.TileSize.Y / 2), 1, SpriteEffects.None, 0f);
                    }
                    currentTile++;
                }                
            }
        }

        public void DrawPlayer(GameTime gameTime, SpriteBatch spriteBatch)
        {
            player.Draw(gameTime, spriteBatch);
        }
    }   
}